//
// Created by Administrator on 2021/4/13.
//
/*给定一个非空特殊的二叉树，每个节点都是正数，并且每个节点的子节点数量只能为2或0。
如果一个节点有两个子节点的话，那么该节点的值等于两个子节点中较小的一个。

更正式地说，root.val = min(root.left.val, root.right.val) 总成立。

给出这样的一个二叉树，你需要输出所有节点中的第二小的值。如果第二小的值不存在的话，输出 -1 。

示例 1：
输入：root = [2,2,5,null,null,5,7]
输出：5
解释：最小的值是 2 ，第二小的值是 5 。

示例 2：
输入：root = [2,2,2]
输出：-1
解释：最小的值是 2, 但是不存在第二小的值。

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/second-minimum-node-in-a-binary-tree
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。*/
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <numeric>
#include <functional>

using namespace std;
struct TreeNode {
    int val; // 节点值
    TreeNode *left; // 左子节点
    TreeNode *right; // 右子节点

    TreeNode() : val(0), left(nullptr), right(nullptr) {}

    explicit TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}

    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

class Solution {
public:
    int findSecondMinimumValue(TreeNode *root) {
        // 暴力：遍历 找到vector倒数第二个值
        // root.val == min(root.left.val, root.right.val)
        // 利用这棵树的性质，一直往较大的一侧走，直到找到这么一个节点：它的较大子树是一个叶节点，那么这棵树第二大的就是这个节点的值
        std::vector<int> ans;
        dfs(root, ans);
        std::sort(ans.begin(), ans.end());
        int n = (int) ans.size(), i = 1;
        while (i < n) {
            if (ans[i] != ans.front()) return ans[i];
            else i++;
        }
        return -1;
    }

    void dfs(TreeNode *root, std::vector<int> &v) {
        if (root == nullptr) return;
        v.push_back(root->val);
        dfs(root->left, v);
        dfs(root->right, v);
    }
};

class Solution2 {  // 优秀解答
public:
    int findSecondMinimumValue(TreeNode *root) {
        if (!root || !root->left || !root->right) return -1;//空节点或不满足题意

        int left = root->left->val, right = root->right->val;

        //若根节点和左节点值相同，则递归找左子树的第二小节点
        if (root->val == root->left->val) left = findSecondMinimumValue(root->left);
        //若根节点和右节点值相同，则递归找右子树的第二小节点
        if (root->val == root->right->val) right = findSecondMinimumValue(root->right);

        //若根节点等于左右子树的第二小节点返回-1
        if (root->val == left && root->val == right) return -1;

        //根据当前的根、左右节点的值继续判断
        int min_lr = std::min(left, right);
        if (root->val < min_lr) return min_lr;//根节点小于最小值，返回最小值
        else return std::max(left, right);//根节点等于最小值，返回最大值
    }

};
class Solution3 {  // 题解
public:
    /**
     * 根节点是最小值
     * 在dfs中找到大于根节点值的最小值
     * @param root
     * @return
     */
    int findSecondMinimumValue(TreeNode* root) {
        int ans = -1;
        int rootValue = root->val;

        function<void(TreeNode*)> dfs = [&](TreeNode* node) {
            if (!node) {
                return;
            }
            if (ans != -1 && node->val >= ans) { // 找最小
                return;
            }
            if (node->val > rootValue) {
                ans = node->val;
            }
            dfs(node->left);
            dfs(node->right);
        };

        dfs(root);
        return ans;
    }
};


int main() {
    auto t5 = TreeNode(7);
    auto t4 = TreeNode(5);
    auto t3 = TreeNode(5, &t4, &t5);
    auto t2 = TreeNode(2);
    auto t1 = TreeNode(2, &t2, &t3);

    auto n3 = TreeNode(2);
    auto n2 = TreeNode(2);
    auto n1 = TreeNode(2, &n2, &n3);

    Solution2 sol;
    std::cout << sol.findSecondMinimumValue(&t1);
    return 0;
}